﻿using System;
using System.Data.SqlClient;
using System.IO;
using System.Windows.Forms;
using CSW.Framework.Common;
using CSW.Framework.Common.Binding.ValueTypes;
using CSW.Framework.Linq.SchemaModel;
using CSW.Framework.UI.Binding;
using LinqBusinessObjectBuilder.Generator;
using LinqBusinessObjectBuilder.Options;
using LinqBusinessObjectBuilder.ProjectInfo;

namespace LinqBusinessObjectBuilder.UserControls
{
    internal partial class ProjectOptionsUserControl : UserControl
    {
        private Binder<Project> m_Binder;

        public ProjectOptionsUserControl()
        {
            InitializeComponent();

            openFileDialog.InitialDirectory = Program.AppDataPath;
            saveFileDialog.InitialDirectory = Program.AppDataPath;
        }

        public void LoadProject(string projectFileName)
        {
            Guard.ArgumentNotNullOrEmptyString(projectFileName, "projectFileName");

            Cursor.Current = Cursors.WaitCursor;
            LoadProject(Project.LoadFromFile(projectFileName));
            Cursor.Current = Cursors.Default;
        }

        public void LoadProject(Project project)
        {
            Guard.ArgumentNotNull(project, "project");

            Cursor.Current = Cursors.WaitCursor;

            Program.OpenProject = project;

            if (!string.IsNullOrEmpty(Program.OpenProject.ProjectFilePath))
            {
                GlobalOptions.Instance.BeginEdit();
                GlobalOptions.Instance.CurrentProjectPath = Program.OpenProject.ProjectFilePath;
                GlobalOptions.Instance.Save();
            }

            if (m_Binder != null)
                m_Binder.Dispose();

            m_Binder = new Binder<Project>(Program.OpenProject, new ErrorWrapper(errorProvider1));
            m_Binder.Bind(new BindableTextBox(txtServerName), p => p.Server);
            m_Binder.Bind(new BindableTextBox(txtUserName), p => p.User);
            m_Binder.Bind(new BindableTextBox(txtPassword), p => p.Password);
            m_Binder.Bind(new BindableComboBox(cmbAuthentication, AuthenticationMode.GetAll(), false), p => p.AuthenticationMode);
            m_Binder.Bind(new BindableComboBox(cmbDatabase, Program.OpenProject.DatabaseList, false), p => p.Database);
            m_Binder.Bind(new BindableTextBox(txtNamespace), p => p.Namespace);
            m_Binder.Bind(new BindableTextBox(txtContextClass), p => p.DataContextName);
            m_Binder.Bind(new BindableComboBox(cmbSerialization, SerializationMode.GetAll(), false), p => p.SerializationMode);
            m_Binder.Bind(new BindableCheckBox(chkPluralize), p => p.UsePluralize);
            m_Binder.Bind(new BindableCheckBox(chkDatabaseStoredProcedures), p => p.GenerateStoredProcedures);
            m_Binder.Bind(new BindableCheckBox(chkDatabaseViews), p => p.GenerateViews);
            m_Binder.Bind(new BindableCheckBox(chkDatabaseFunctions), p => p.GenerateFunctions);
            m_Binder.Bind(new BindableTextBox(txtOutputFolder), p => p.OutputPath);
            m_Binder.Bind(new BindableTextBox(txtSolutionName), p => p.SolutionName);

            m_Binder.UpdateControls();

            if (!Program.OpenProject.IsEditting)
                Program.OpenProject.BeginEdit();

            Cursor.Current = Cursors.Default;
        }

        public void AskSaveChanges(out bool cancel)
        {
            cancel = false;

            Application.DoEvents();

            m_Binder.ValidateAllControls();

            if (Program.OpenProject.IsEditting &&
                Program.OpenProject.ObjectState != BindableObjectState.Pristine)
            {
                DialogResult res = MessageBox.Show("Save changes?", "", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);

                if (res == DialogResult.Yes)
                {
                    if (!Save())
                        cancel = true;
                }
                else if (res != DialogResult.No)
                {
                    cancel = true;
                }
            }

            Application.DoEvents();
        }

        public void Generate()
        {
            Application.DoEvents();

            // since we have a keyboard shortcut here..
            m_Binder.ValidateAllControls();

            if (string.IsNullOrEmpty(Program.OpenProject.Server))
            {
                MessageBox.Show("Please enter the server name.", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
                txtServerName.Focus();
                return;
            }

            if (string.IsNullOrEmpty(Program.OpenProject.Database))
            {
                MessageBox.Show("Please select the database.", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
                cmbDatabase.Focus();
                return;
            }

            if (string.IsNullOrEmpty(Program.OpenProject.Namespace))
            {
                MessageBox.Show("Please enter a namespace.", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
                txtNamespace.Focus();
                return;
            }

            if (string.IsNullOrEmpty(Program.OpenProject.DataContextName))
            {
                MessageBox.Show("Please enter a data context name.", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
                txtContextClass.Focus();
                return;
            }

            if (string.IsNullOrEmpty(Program.OpenProject.OutputPath))
            {
                MessageBox.Show("Please enter the output path.", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
                txtOutputFolder.Focus();
                return;
            }

            if (!File.Exists(GlobalOptions.Instance.CSWCommonPath))
            {
                MessageBox.Show("Please set CSW.Framework.Common.csproj location.", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
                Program.ShowGlobalOptionsForm();
                return;
            }

            if (!File.Exists(GlobalOptions.Instance.MSBuildPath))
            {
                MessageBox.Show("Please set the MSBuild location.", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
                Program.ShowGlobalOptionsForm();
                return;
            }

            Cursor.Current = Cursors.WaitCursor;

            string solutionFile = CodeGenerator.Generate(Program.OpenProject, GlobalOptions.Instance);

            Cursor.Current = Cursors.Default;
        }

        private void btnTestConnection_Click(object sender, EventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;
            try
            {
                Program.OpenProject.RefreshDatabases();
            }
            catch (SqlException ex)
            {
                Cursor.Current = Cursors.Default;
                MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            Cursor.Current = Cursors.Default;
        }

        private void btnBrowseOutputFolder_Click(object sender, EventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;
            using (FolderBrowserDialog folder = new FolderBrowserDialog())
            {
                folder.ShowNewFolderButton = true;
                Cursor.Current = Cursors.Default;
                if (folder.ShowDialog() == DialogResult.OK)
                {
                    Program.OpenProject.OutputPath = folder.SelectedPath;
                }
            }
        }

        public bool Save()
        {
            m_Binder.ValidateAllControls();

            if (string.IsNullOrEmpty(Program.OpenProject.ProjectFilePath))
            {
                return SaveAs();
            }
            else
            {
                Cursor.Current = Cursors.WaitCursor;
                Program.OpenProject.Save();
                LoadProject(Program.OpenProject.ProjectFilePath);
                Cursor.Current = Cursors.Default;
                return true;
            }
        }

        public bool SaveAs()
        {
            m_Binder.ValidateAllControls();

            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                Program.OpenProject.ProjectFilePath = saveFileDialog.FileName;
                return Save();
            }
            else
            {
                return false;
            }
        }

        public void OpenProject()
        {
            m_Binder.ValidateAllControls();

            bool cancel;
            AskSaveChanges(out cancel);

            if (!cancel)
            {
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    LoadProject(openFileDialog.FileName);
                }
            }
        }

        public void CreateNewProject()
        {
            m_Binder.ValidateAllControls();

            bool cancel;
            AskSaveChanges(out cancel);

            if (!cancel)
            {
                LoadProject(new Project());
            }
        }

        private void btnUpdateSchema_Click(object sender, EventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;
            Database db = CodeGenerator.GetUpdatedSchema(Program.OpenProject);
            Program.OpenProject.Schema = db;
            Cursor.Current = Cursors.Default;
        }
    }
}
